Michał Bultrowicz

Zadawajcie pytania w trakcie prezentacji


Ideologia

  • Tylko Python3
  • Pisz kod raz, udostępniaj przez wiele interfejsów
    • HTTP
    • CLI
    • Zwykły kod Pythona
  • Zachowanie dużej szybkości (Falcon jako baza)


In [ ]:
#app.py
import hug

@hug.get('/')
def spam():
    return 'ham!'

In [ ]:
!hug -f app.py

In [ ]:
spam()

In [ ]:
#app_cli.py
import hug

@hug.cli()
@hug.get('/')
def spam():
    return 'ham!'

In [ ]:
!hug -f app_cli.py

In [ ]:
!hug -f app_cli.py -c spam

Czas pokaże czy wiele rodzajów interfejsów to sensowne podejście.


Szybkie tworzenie minimalnych serwisów

  • Alternatywa dla Bottle, Flaska itd.
  • Framework ma kod wyższej jakości
  • Duża wydajność

Uwaga! Aplikacje robione "na szybko" zazwyczaj żyją dłużej, niż powinny.


Walidacja wejścia


In [ ]:
# przez get i URL jak w dokumentacji, ale to nie REST
import hug

@hug.get()
def hello(name: hug.types.text, age: int):
    return "Hello {}! You've lived for {} years.".format(name, age)

hug.API(__name__).http.serve()

In [ ]:
import socketserver
socketserver.TCPServer.allow_reuse_address = True

# zwolnienie socketu zajętego przez proces Notebooka
import gc
gc.collect()

In [ ]:
@hug.get('/smallish-number/{number}')
def hello(number: hug.types.in_range(1,30)):
    return {'bigger_number': number+1}

hug.API(__name__).http.serve()

In [ ]:
gc.collect()

In [ ]:
@hug.post('/rectangle', status=hug.HTTP_201)
def hello(a: int, b: int):
    return {'width': a, 'height': b}

hug.API(__name__).http.serve()

In [ ]:
gc.collect()

Można definiować swoje typy przez:

  • rozszerzanie istniejacych typów z hug.types
  • tworzenie klas Marshmallow


Bardziej zaawansowana interakcja z HTTP


In [85]:
@hug.get('/', response_headers={'X-bblabla': 'jakas wartosc'})
def spam():
    return 'ham!'

hug.API(__name__).http.serve()


/#######################################################################\
          `.----``..-------..``.----.
         :/:::::--:---------:--::::://.
        .+::::----##/-/oo+:-##----:::://
        `//::-------/oosoo-------::://.       ##    ##  ##    ##    #####
          .-:------./++o/o-.------::-`   ```  ##    ##  ##    ##  ##
             `----.-./+o+:..----.     `.:///. ########  ##    ## ##
   ```        `----.-::::::------  `.-:::://. ##    ##  ##    ## ##   ####
  ://::--.``` -:``...-----...` `:--::::::-.`  ##    ##  ##   ##   ##    ##
  :/:::::::::-:-     `````      .:::::-.`     ##    ##    ####     ######
   ``.--:::::::.                .:::.`
         ``..::.                .::         EMBRACE THE APIs OF THE FUTURE
             ::-                .:-
             -::`               ::-                   VERSION 2.2.0
             `::-              -::`
              -::-`           -::-
\########################################################################/

 Copyright (C) 2016 Timothy Edmund Crosley
 Under the MIT License


Serving on port 8000...
127.0.0.1 - - [28/Nov/2016 16:53:54] "POST / HTTP/1.1" 405 0
127.0.0.1 - - [28/Nov/2016 16:54:15] "GET / HTTP/1.1" 200 6
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-85-3b99f337fcf2> in <module>()
      3     return 'ham!'
      4 
----> 5 hug.API(__name__).http.serve()
      6 
      7 # ustawienie headerów

/home/butla/.virtualenvs/hug/lib/python3.5/site-packages/hug/api.py in serve(self, port, no_documentation)
    240         httpd = make_server('', port, api)
    241         print("Serving on port {0}...".format(port))
--> 242         httpd.serve_forever()
    243 
    244     @staticmethod

/usr/lib/python3.5/socketserver.py in serve_forever(self, poll_interval)
    230 
    231                 while not self.__shutdown_request:
--> 232                     ready = selector.select(poll_interval)
    233                     if ready:
    234                         self._handle_request_noblock()

/usr/lib/python3.5/selectors.py in select(self, timeout)
    374             ready = []
    375             try:
--> 376                 fd_event_list = self._poll.poll(timeout)
    377             except InterruptedError:
    378                 return ready

KeyboardInterrupt: 

In [121]:
gc.collect()


Out[121]:
444

In [118]:
@hug.directive()
def http_req(**kwargs):
    return kwargs['request']

@hug.directive()
def http_resp(**kwargs):
    return kwargs['response']

@hug.get('/')
def spam(hug_http_req, hug_http_resp):
    print(hug_http_req)
    print(hug_http_resp)
    
    print(hug_http_req.headers)
    hug_http_resp.status = hug.HTTP_418
    return 'ham!'

hug.API(__name__).http.serve()

# czytanie headerów z dyrektywy
# hug_session - ustawianie statusu, też czytanie headerów


/#######################################################################\
          `.----``..-------..``.----.
         :/:::::--:---------:--::::://.
        .+::::----##/-/oo+:-##----:::://
        `//::-------/oosoo-------::://.       ##    ##  ##    ##    #####
          .-:------./++o/o-.------::-`   ```  ##    ##  ##    ##  ##
             `----.-./+o+:..----.     `.:///. ########  ##    ## ##
   ```        `----.-::::::------  `.-:::://. ##    ##  ##    ## ##   ####
  ://::--.``` -:``...-----...` `:--::::::-.`  ##    ##  ##   ##   ##    ##
  :/:::::::::-:-     `````      .:::::-.`     ##    ##    ####     ######
   ``.--:::::::.                .:::.`
         ``..::.                .::         EMBRACE THE APIs OF THE FUTURE
             ::-                .:-
             -::`               ::-                   VERSION 2.2.0
             `::-              -::`
              -::-`           -::-
\########################################################################/

 Copyright (C) 2016 Timothy Edmund Crosley
 Under the MIT License


---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-118-c6e04bd1a7db> in <module>()
     16     return 'ham!'
     17 
---> 18 hug.API(__name__).http.serve()
     19 
     20 # czytanie headerów z dyrektywy

/home/butla/.virtualenvs/hug/lib/python3.5/site-packages/hug/api.py in serve(self, port, no_documentation)
    238 
    239         print(INTRO)
--> 240         httpd = make_server('', port, api)
    241         print("Serving on port {0}...".format(port))
    242         httpd.serve_forever()

/usr/lib/python3.5/wsgiref/simple_server.py in make_server(host, port, app, server_class, handler_class)
    158 ):
    159     """Create a new WSGI server listening on `host` and `port` for `app`"""
--> 160     server = server_class((host, port), handler_class)
    161     server.set_app(app)
    162     return server

/usr/lib/python3.5/socketserver.py in __init__(self, server_address, RequestHandlerClass, bind_and_activate)
    438         if bind_and_activate:
    439             try:
--> 440                 self.server_bind()
    441                 self.server_activate()
    442             except:

/usr/lib/python3.5/wsgiref/simple_server.py in server_bind(self)
     49     def server_bind(self):
     50         """Override server_bind to store the server name."""
---> 51         HTTPServer.server_bind(self)
     52         self.setup_environ()
     53 

/usr/lib/python3.5/http/server.py in server_bind(self)
    136     def server_bind(self):
    137         """Override server_bind to store the server name."""
--> 138         socketserver.TCPServer.server_bind(self)
    139         host, port = self.socket.getsockname()[:2]
    140         self.server_name = socket.getfqdn(host)

/usr/lib/python3.5/socketserver.py in server_bind(self)
    452         if self.allow_reuse_address:
    453             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
--> 454         self.socket.bind(self.server_address)
    455         self.server_address = self.socket.getsockname()
    456 

OSError: [Errno 98] Address already in use

In [115]:
gc.collect()


Out[115]:
441

Poczytaj mi mamo: RTFM

  • typy outputów (hug z automatu ustawia headery i takietam)
  • requires
  • tranformations
  • Tworzenie poważnych aplikacji z testami, walidacją wejścia. Odpalanie produkcyjne huga. Autoryzacja

Reszta

Zaprawdzam do zapoznania się z resztą dokumentacji (więcej szczegółów) http://www.hug.rest/website/learn/architecture

Jest po kilka sposobów używania Huga, żeby było wygodniej. Ale można też używać API bardziej "verbose".


In [ ]: